package io.github.wppli.domain.recommond.rservice.referral;

import cc.jq1024.middleware.redisson.IRedissonService;
import io.github.wppli.domain.recommond.rservice.AbstractUserRecommendService;
import io.github.wppli.domain.recommond.rservice.datamodel.DataModelService;
import io.github.wppli.domain.user.repository.IUserRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.CachingRecommender;
import org.apache.mahout.cf.taste.impl.recommender.GenericItemBasedRecommender;
import org.apache.mahout.cf.taste.impl.recommender.GenericRecommendedItem;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.LogLikelihoodSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.ItemSimilarity;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author li--jiaqiang 2025−03−14
 */
@Slf4j
@Service
public class UserRecommendService extends AbstractUserRecommendService {

    private final DataModelService dataModelService;

    public UserRecommendService(IRedissonService redissonService, IUserRepository userRepository, DataModelService dataModelService) {
        super(redissonService, userRepository);
        this.dataModelService = dataModelService;
    }


    /**
     * 找到相似被关注用户，推荐用户可能喜欢的用户 -》 XXX用户关注了itemId用户，看哪些用户也被XXX用户关注，推荐这些用户
     *  -》 关注了itemId用户人还关注了以下用户
     * 基于用户关注物品的相似性
     * @param itemId       目标物品ID(被关注用户ID) followee_id -》
     * @param recommendNum 推荐数量
     */
    @Override
    public List<RecommendedItem> recommendUsersByItemCF(Long itemId, int recommendNum) throws ClassNotFoundException, TasteException {
        DataModel dataModel = dataModelService.getDataModelFromDataSource(
                "user_follows",
                "follower_id",
                "followee_id",
                "behavior_weight",
                "created_at"
        );
        // 1. 计算物品相似度（这里物品是被关注的用户）
        ItemSimilarity itemSimilarity = new LogLikelihoodSimilarity(dataModel);

        // 2. 构建推荐器，使用基于物品的协同过滤推荐
        CachingRecommender recommender = new CachingRecommender(
                new GenericItemBasedRecommender(dataModel, itemSimilarity)
        );
        // 3. 生成推荐结果
        return recommender.recommend(itemId, recommendNum);
    }

    /**
     * 用户点击itemId用户主页时，调用该方法进行推荐
     * 用户推荐：基于关注用户的相似性 -》 XXX用户关注了userId用户，XXX用用户又关注了哪些用户，那么这些用户就是相似的用户
     * @param userId          被关注用户ID
     * @param neighborhoodNum 邻居数量
     * @param recommendNum    推荐数量
     */
    @Override
    public List<RecommendedItem> recommendUsersByUserCF(Long userId, int neighborhoodNum, int recommendNum) throws ClassNotFoundException, TasteException {
        DataModel dataModel = dataModelService.getDataModelFromDataSource(
                "user_follows",
                "follower_id",
                "followee_id",
                "behavior_weight",
                "created_at"
        );
        // 1. 计算用户相似度（余弦相似度）
        UserSimilarity similarity = new LogLikelihoodSimilarity(dataModel);
        // 2. 选择邻居算法
        UserNeighborhood neighborhood = new NearestNUserNeighborhood(neighborhoodNum, similarity, dataModel);
        // 3. 构建推荐器
        Recommender recommender = new CachingRecommender(
                new GenericUserBasedRecommender(dataModel, neighborhood, similarity)
        );
        // 4. 生成推荐结果（排除已关注的用户）
        return recommender.recommend(userId, recommendNum);
    }



    // 结合 UserCF 和 ItemCF 的加权得分
    public List<RecommendedItem> hybridRecommend(Long userId,int neighborhoodNum, int num) throws ClassNotFoundException, TasteException {
        List<RecommendedItem> userCFItems = recommendUsersByUserCF(userId, neighborhoodNum, num * 2);
        List<RecommendedItem> itemCFItems = recommendUsersByItemCF(userId, num * 2);

        // 合并并去重（示例：简单加权）
        Map<Long, Float> scoreMap = new HashMap<>();
        userCFItems.forEach(item -> scoreMap.put(item.getItemID(), item.getValue() * 0.6f));
        itemCFItems.forEach(item ->
                scoreMap.put(item.getItemID(), scoreMap.getOrDefault(item.getItemID(), 0.0f) + item.getValue() * 0.4f)
        );

        // 按得分排序
        return scoreMap.entrySet().stream()
                .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
                .limit(num)
                .map(entry -> new GenericRecommendedItem(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

}